#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <parse.h>
#include <sys/stat.h>
#include<time.h>
#include<sys/select.h>
#include<sys/types.h>

#define ECHO_PORT 9999
#define BUF_SIZE 4096
#define MAX_CLIENT 1024

int sock = -1, client_sock = -1;
char buf[BUF_SIZE];
char allreq[2 * BUF_SIZE];
fd_set master_fds, read_fds;

//new code try
//第二部分还有缓冲区管理，读写磁盘文件问题和简化日志记录没有做
/*void log_access(const struct sockaddr_in *cli_addr, const Request *req, int status_code, long content_length) {
    FILE *log = fopen("./zlog/access.log", "a");
    if (!log) {
        printf("Failed to open access.log");
        return;
    }

    // 获取客户端IP
    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &cli_addr->sin_addr, client_ip, INET_ADDRSTRLEN);

    // 生成时间戳
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    char time_buf[64];
    strftime(time_buf, sizeof(time_buf), "%d/%b/%Y:%H:%M:%S %z", tm);

    // 构建请求行
    char request_line[256];
    snprintf(request_line, sizeof(request_line), "%s %s %s",
             req->http_method, req->http_uri, req->http_version);

    // 写入访问日志
    fprintf(log, "%s - - [%s] \"%s\" %d %ld\n",
            client_ip, time_buf, request_line, status_code, content_length);
    fclose(log);
}

void log_error(const struct sockaddr_in *cli_addr, const char *module, const char *message) {
    FILE *log = fopen("./zlog/error.log", "a");
    if (!log) {
        printf("Failed to open error.log");
        return;
    }

    // 获取客户端IP
    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &cli_addr->sin_addr, client_ip, INET_ADDRSTRLEN);

    // 生成时间戳
    time_t now = time(NULL);
    struct tm *tm = localtime(&now);
    char time_buf[64];
    strftime(time_buf, sizeof(time_buf), "[%a %b %d %H:%M:%S %Y]", tm);

    // 写入错误日志
    fprintf(log, "%s [%s:error] [pid %d] [client %s] %s\n",
            time_buf, module, getpid(), client_ip, message);
    fclose(log);
}*/

void ReqHead(char *rethead){
    //向客户端发送head格式的相应
    struct stat filebuf;
    stat("./static_site/index.html", &filebuf);//直接用本地的东西

    time_t now;
    time(&now);//获取当前时间
    struct tm *gm_now = gmtime(&now);
    char now_time[30];
    strftime(now_time, sizeof(now_time), "%a, %d %b %Y %H:%M:%S GMT", gm_now);

    struct tm *gm_time = gmtime(&filebuf.st_mtime);
    char md_time[30];
    strftime(md_time, sizeof(md_time), "%a, %d %b %Y %H:%M:%S GMT", gm_time);

    memset(rethead, 0, BUF_SIZE);

    // 构造响应头部
    snprintf(rethead, BUF_SIZE,
        "HTTP/1.1 200 OK\r\n"
        "Server: liso/1.1\r\n"
        "Date: %s\r\n"
        "Content-Length: %ld\r\n"
        "Content-Type: text/html\r\n"
        "Last-Modified: %s\r\n"
        "Connection: keep-alive\r\n"
        "\r\n",
        now_time,
        filebuf.st_size,
        md_time); // 获取文件最后修改时间
}

size_t ReqContent(char *content,int client_sock){
    // 读取文件内容
    FILE *file = fopen("./static_site/index.html", "rb");
    if (file == NULL) {
        // 文件打开失败，返回500
        char response500[BUF_SIZE] = "HTTP/1.1 500 Internal Server Error\r\n\r\n";
        send(client_sock, response500, strlen(response500), 0);
        fprintf(stdout, "send back\n");
    }

    //char content[BUF_SIZE];
    memset(content, 0, BUF_SIZE);
    size_t bytes_read = fread(content, 1, BUF_SIZE, file);
    fclose(file);
    return bytes_read;
}

void HTTP(char *allreq, int client_sock){
    //allreq是请求，
    const char *separator = "\r\n\r\n";
    char *current = allreq;//存的是所有送来的数据
    char *next=0;
    while((next = strstr(current,separator)) != NULL){
        //找到请求头结束的位置，即第一个空行之后
        //查找子串的首次出现位置next
        int length = next-current+4;//这个+4是严格加上那个separator的长度
        memset(buf, 0, BUF_SIZE);
        strncpy(buf,current,length);
        current = next + strlen(separator);//更新current

        //解析请求
        Request *request = parse(buf, strlen(buf),client_sock);
        if(request == NULL){
            //格式错误400，先判断空
            // send(client_sock,"HTTP1.1 400 Bad request\r\n\r\n",30,0);
            char response400[BUF_SIZE] = "HTTP/1.1 400 Bad request\r\n\r\n";
            send(client_sock, response400, strlen(response400), 0);
            //log_error(&cli_addr, "request", "Bad request: invalid format"); 
            fprintf(stdout,"send back\n");
            // close_socket(client_sock);
            //break;
        }
        else{
            //send(client_sock,request->http_method,strlen(request->http_method),0);

            if(strcmp(request->http_version,"HTTP/1.1")){
                //HTTP版本不支持505
                char response505[BUF_SIZE] = "HTTP/1.1 505 HTTP Version not supported\r\n\r\n";
                send(client_sock, response505, strlen(response505), 0);
                //log_error(&cli_addr, "core", "Unsupported HTTP version");
                fprintf(stdout,"send back\n");
                //break;
            }
                    
            else if(strcmp(request->http_method,"POST") && strcmp(request->http_method,"GET") && strcmp(request->http_method,"HEAD")){
                //不存在这样的指令，501
                char response501[BUF_SIZE] = "HTTP/1.1 501 Not Implemented\r\n\r\n";
                send(client_sock, response501, strlen(response501), 0);
                //log_error(&cli_addr, "method", "Unimplemented method"); 
                fprintf(stdout, "Http Method %s\n",request->http_method);
                //break;
            }

            else if(strcmp(request->http_uri,"/")){
                //请求内容不存在404
                char response404[BUF_SIZE] = "HTTP/1.1 404 Not Found\r\n\r\n";
                send(client_sock, response404, strlen(response404), 0);
                //log_error(&cli_addr, "file", "File not found");
                fprintf(stdout,"send back\n");
                //break;
            }

            else if(!strcmp(request->http_method,"GET")){
                //向客户端发送get格式的相应
                char rethead[BUF_SIZE];
                ReqHead(rethead);
                // 读取文件内容
                char content[BUF_SIZE];
                size_t bytes_read = ReqContent(content,client_sock);
                // 合并响应头部和内容
                char final_response[BUF_SIZE];
                memset(final_response, 0, BUF_SIZE);
                strcat(final_response, rethead);
                strncat(final_response, content, bytes_read);

                // 发送响应
                if (send(client_sock, final_response, strlen(final_response), 0) < 0) {
                    break;
                }
                //log_access(&cli_addr, request, 200, filebuf.st_size);  // 
                fprintf(stdout,"send back\n");
                //break;
            }

            else if(!strcmp(request->http_method,"POST")){
                //向客户端发送post格式的相应
                strcat(buf,"(echo back)");
                        
                if(send(client_sock, buf, strlen(buf), 0) < 0)break;
                //log_access(&cli_addr, request, 200, strlen(buf));  // 记录echo长度
                fprintf(stdout,"Send back\n");
                //break;
            }

            else if(!strcmp(request->http_method,"HEAD")){
                //向客户端发送head格式的相应
                char rethead[BUF_SIZE];
                ReqHead(rethead);

                send(client_sock, rethead, strlen(rethead), 0);
                //log_access(&cli_addr, request, 200, 0);  // HEAD不返回内容
                fprintf(stdout,"send back\n");
                //break;
            }
        }
        // if(request == NULL){
        //     free(request->headers);
        // }
        // free(request);
    }

    /*以上是HTTP协议逻辑*/
}


int close_socket(int sock) {
    if (close(sock)) {
        fprintf(stderr, "Failed closing socket.\n");
        return 1;
    }
    return 0;
}
void handle_signal(const int sig) {
    if (sock != -1) {
        fprintf(stderr, "\nReceived signal %d. Closing socket.\n", sig);
        close_socket(sock);
    }
    exit(0);
}
void handle_sigpipe(const int sig) 
{
    if (sock != -1) {
        return;
    }
    exit(0);
}
int main(int argc, char *argv[]) {
    /* register signal handler */
    /* process termination signals */
    signal(SIGTERM, handle_signal);
    signal(SIGINT, handle_signal);
    signal(SIGSEGV, handle_signal);
    signal(SIGABRT, handle_signal);
    signal(SIGQUIT, handle_signal);
    signal(SIGTSTP, handle_signal);
    signal(SIGFPE, handle_signal);
    signal(SIGHUP, handle_signal);
    /* normal I/O event */
    signal(SIGPIPE, handle_sigpipe);
    socklen_t cli_size;
    struct sockaddr_in addr, cli_addr;
    fprintf(stdout, "----- Echo Server -----\n");

    /* all networked programs must create a socket */
    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        fprintf(stderr, "Failed creating socket.\n");
        return EXIT_FAILURE;
    }
    /* set socket SO_REUSEADDR | SO_REUSEPORT */
    int opt = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        fprintf(stderr, "Failed setting socket options.\n");
        return EXIT_FAILURE;
    }

    addr.sin_family = AF_INET; // ipv4
    addr.sin_port = htons(ECHO_PORT);
    addr.sin_addr.s_addr = INADDR_ANY;

    /* servers bind sockets to ports---notify the OS they accept connections */
    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr))) {
        close_socket(sock);
        fprintf(stderr, "Failed binding socket.\n");
        return EXIT_FAILURE;
    }

    if (listen(sock, 5)) {
        close_socket(sock);
        fprintf(stderr, "Error listening on socket.\n");
        return EXIT_FAILURE;
    }

    /* finally, loop waiting for input and then write it back */

    fprintf(stdout,"Waiting for connection...\n");

    FD_ZERO(&master_fds);
    FD_SET(sock,&master_fds);//将套接字的文件描述符加入要监视的集合之中，检查是否有客户端向服务器发起连接
    int ready_num=0;
    int max_fd = sock;
    while(1){
        read_fds = master_fds;
        ready_num = select(max_fd+1,&read_fds,NULL,NULL,NULL);
        if(ready_num < 0){
            //若没有可操作文件，继续循环select
            continue;
        }
        else{
            //有可操作文件，分为新连接和老请求
            for(int i=0;i<=max_fd;i++){/*跳过标准输入输出开始循环遍历set*/
                if(FD_ISSET(i,&read_fds)){/*有事件发生*/
                    if(i == sock){
                        //如果是新客户连接
                        cli_size = sizeof(cli_addr);
                        client_sock = accept(sock, (struct sockaddr *) &cli_addr, &cli_size);
                            
                        if (client_sock == -1)
                        {
                            fprintf(stderr, "Error accepting connection.\n");
                            close_socket(sock);
                            return EXIT_FAILURE;
                        }
                        //成功建立新连接
                        if (client_sock > max_fd) { // 更新最大的文件描述符值，确保 select() 能监控到所有文件描述符
                            max_fd = client_sock;
                        }
                        FD_SET(client_sock,&master_fds);//将客户端的文件描述符添加到read_fds中
                        fprintf(stdout,"New connection from %s:%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
                        fprintf(stdout,"New connection : socket fd is %d\n",client_sock);
                    }

                    else{/*有客户端发来内容*/
                            memset(allreq, 0, 2*BUF_SIZE);
                            //recv接收数据
                            int readret = recv(i, allreq, BUF_SIZE, 0);
                            if (readret <=0){
                                FD_CLR(i,&master_fds);
                                fprintf(stdout, "Connection closed by %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
                                close(i);
                            }
                            else{
                                fprintf(stdout,"Received (total %d bytes):%s \n",readret,allreq); 
                                /*以下是调用HTTP协议处理响应*/
                                HTTP(allreq,i);
                                fprintf(stdout, "Send back\n");
                                    /*响应完成*/
                            }//一个响应结束
                                
                    }//对一个客户端set处理结束
                }//对事件处理结束
            }//遍历完set

        }//对可操作文件处理结束
            
    }

    close_socket(sock);
    return EXIT_SUCCESS;
}
